package flutter.plugins.screen.screen;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.Application;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.net.Uri;
import android.os.Process;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.provider.Settings;
import android.util.Log;
import android.view.WindowManager;

import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;

import java.lang.reflect.Method;
import java.util.ArrayList;

import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.PluginRegistry.Registrar;

import static android.content.Context.POWER_SERVICE;

/**
 * ScreenPlugin
 */
public class ScreenPlugin implements MethodCallHandler, StreamHandler {
  public static String EXTRA_MESSAGE = "flutter.plugins.screen.screen.MESSAGE";

  private static final String METHOD = "github.com/clovisnicolas/flutter_screen";
  private static final String EVENT = "github.com/clovisnicolas/flutter_screen/event";

  private ScreenPlugin(Registrar registrar){
    this._registrar = registrar;
  }
  private Registrar _registrar;
  private WakeLock _wakeLock;
  private BroadcastReceiver callStateChangeReceiver;
  private EventChannel.EventSink _eventSink;


  public static void registerWith(Registrar registrar) {
    ScreenPlugin screenPlugin = new ScreenPlugin(registrar);
    final MethodChannel channel = new MethodChannel(registrar.messenger(), METHOD);
    channel.setMethodCallHandler(screenPlugin);
    final EventChannel eventChannel = new EventChannel(registrar.messenger(), EVENT);
    eventChannel.setStreamHandler(screenPlugin);
  }

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    switch(call.method){
      case "hasPermission":
          hasPermission(call, result);
          break;
      case "hasPermissions":
        hasPermissions(call, result);
        break;
      case "hasOpPermission":
        int op = call.argument("op");
        result.success(hasOpPermission(op));
        break;
      case "canDrawOverlays":
          boolean can = canDrawOverlays();
          result.success(can);
          break;
        case "acquireWakeLock":
            acquireWakeLock();
            result.success(_wakeLock != null);
            break;
        case "releaseWakeLock":
            releaseWakeLock();
            result.success(_wakeLock == null);
            break;
      case "wakeUpAndUnlock":
        wakeUpAndUnlock();
        break;
      case "callingIn":
        String name = call.argument("name");
        String tips = call.argument("tips");
        callingIn(name, tips);
        break;
      case "callConnected":
        callConnected();
        break;
      case "registerCallingInReceiver":
        registerCallingInReceiver();
        break;
      case "unregisterCallingInReceiver":
        unregisterCallingInReceiver();
        break;
      case "brightness":
        result.success(getBrightness());
        break;
      case "setBrightness":
        double brightness = call.argument("brightness");
        WindowManager.LayoutParams layoutParams = _registrar.activity().getWindow().getAttributes();
        layoutParams.screenBrightness = (float)brightness;
        _registrar.activity().getWindow().setAttributes(layoutParams);
        result.success(null);
        break;
      case "isKeptOn":
        int flags = _registrar.activity().getWindow().getAttributes().flags;
        result.success((flags & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0) ;
        break;
      case "keepOn":
        Boolean on = call.argument("on");
        if (on) {
          System.out.println("Keeping screen on ");
          _registrar.activity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
        else{
          System.out.println("Not keeping screen on");
          _registrar.activity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
        result.success(null);
        break;
      case "ignoreBatteryOptimization":
        ignoreBatteryOptimization();
        result.success(null);
        break;
      default:
        result.notImplemented();
        break;
    }
  }

  private float getBrightness(){
    float result = _registrar.activity().getWindow().getAttributes().screenBrightness;
    if (result < 0) { // the application is using the system brightness
      try {
        result = Settings.System.getInt(_registrar.context().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS) / (float)255;
      } catch (Settings.SettingNotFoundException e) {
        result = 1.0f;
        e.printStackTrace();
      }
    }
    return result;
  }


  //获取电源锁，保持该服务在屏幕熄灭时仍然获取CPU时，保持运行
  @SuppressLint("InvalidWakeLockTag")
  private void acquireWakeLock()
  {
    if (null == _wakeLock)
    {

      PowerManager pm = (PowerManager)this._registrar.activeContext().getSystemService(POWER_SERVICE);
      _wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "PostLocationService");
      if (null != _wakeLock)
      {
        _wakeLock.acquire();
      }
    }
  }

  //释放设备电源锁
  private void releaseWakeLock()
  {
    if (null != _wakeLock)
    {
      _wakeLock.release();
      _wakeLock = null;
    }
  }

  private void wakeUpAndUnlock() {
    //屏锁管理器
    KeyguardManager km= (KeyguardManager) this._registrar.activeContext().getSystemService(Context.KEYGUARD_SERVICE);
    KeyguardManager.KeyguardLock kl = km.newKeyguardLock("unLock");
    //解锁
    kl.disableKeyguard();
    //获取电源管理器对象
    PowerManager pm=(PowerManager) this._registrar.activeContext().getSystemService(POWER_SERVICE);
    //获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag
    @SuppressLint("InvalidWakeLockTag") PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP |
            PowerManager.SCREEN_DIM_WAKE_LOCK,"bright");
    //点亮屏幕
    wl.acquire();
    //释放
    wl.release();
  }

  private void callingIn(String name, String tips) {
    Intent intent = new Intent();
    intent.setAction(CallingInReceiver.ACTION_CALLING_IN);
    intent.putExtra("name", name);
    intent.putExtra("tips", tips);
    this._registrar.activeContext().sendBroadcast(intent);
  }

  private void callConnected() {
    Intent intent = new Intent();
    intent.setAction(CallingInReceiver.ACTION_CALL_CONNECTED);
    this._registrar.activeContext().sendBroadcast(intent);
  }

  CallingInReceiver callingInReceiver;
  private void registerCallingInReceiver() {
    if(callingInReceiver == null) {
      callingInReceiver = new CallingInReceiver();
      IntentFilter intentFilter = new IntentFilter();
      intentFilter.addAction(CallingInReceiver.ACTION_CALLING_IN);
      intentFilter.addAction(CallingInReceiver.ACTION_CALL_CONNECTED);
      this._registrar.activeContext().registerReceiver(callingInReceiver, intentFilter);
    }

    if(callStateChangeReceiver == null) {
      callStateChangeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
          if(_eventSink != null) {
            String action = intent.getAction();
            if(action == CallingInReceiver.ACTION_CALL_STATE_CHANGE) {
              String state = intent.getStringExtra("state");
              _eventSink.success(state);
            }
          }
        }
      };
      IntentFilter intentFilter = new IntentFilter();
      intentFilter.addAction(CallingInReceiver.ACTION_CALL_STATE_CHANGE);
      this._registrar.activeContext().registerReceiver(callStateChangeReceiver, intentFilter);
    }
  }

  private void unregisterCallingInReceiver() {
    if(callingInReceiver != null)
      this._registrar.activeContext().unregisterReceiver(callingInReceiver);
    if(callStateChangeReceiver != null) {
      this._registrar.activeContext().unregisterReceiver(callStateChangeReceiver);
    }
  }

  private void hasPermission(MethodCall call, Result result) {
    String permission = call.argument("permission");
    final int permissionStatus = ContextCompat.checkSelfPermission(this._registrar.activity(), permission);
    Boolean isGranted = permissionStatus == PackageManager.PERMISSION_GRANTED;
    result.success(isGranted);
  }

  private boolean canDrawOverlays() {
    if (Build.VERSION.SDK_INT >= 23) {
      return Settings.canDrawOverlays(this._registrar.activeContext());
    }
    return true;
  }


  @Override
  public void onListen(Object o, final EventChannel.EventSink eventSink) {
    _eventSink = eventSink;
    Log.i("Screen", "onListen");
  }

  @Override
  public void onCancel(Object o) {
    _eventSink = null;
    Log.i("Screen", "onCancel");
  }

  @RequiresApi(api = Build.VERSION_CODES.KITKAT)
  public boolean hasOpPermission(int op) {
    Context context = this._registrar.activeContext();
    AppOpsManager ops = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
    try {
      Method method = ops.getClass().getMethod("checkOpNoThrow", new Class[]{int.class, int.class, String.class});
      Integer result = (Integer) method.invoke(ops, op, Process.myUid(), context.getPackageName());
      return result == AppOpsManager.MODE_ALLOWED;
    } catch (Exception e) {
      return false;
    }
  }

  private void hasPermissions(MethodCall call, Result result) {
    ArrayList<String> permissions = call.argument("permissions");
    boolean isGranted = true;
    for(int i=0;i<permissions.size();i++) {
      int permissionStatus = ContextCompat.checkSelfPermission(this._registrar.activity(), permissions.get(i));
      isGranted = permissionStatus == PackageManager.PERMISSION_GRANTED;
      if(!isGranted) break;
    }
    result.success(isGranted);
  }

  public void ignoreBatteryOptimization() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        try {
          Context context = this._registrar.activeContext();
            PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
            boolean hasIgnored = powerManager.isIgnoringBatteryOptimizations(this._registrar.activity().getPackageName());
            /**
             * 判断当前APP是否有加入电池优化的白名单，
             * 如果没有，弹出加入电池优化的白名单的设置对话框
             * */
            if (!hasIgnored) {
                Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + this._registrar.activity().getPackageName()));
              context.startActivity(intent);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  }

}
